package io.github.kouleen.manager.service;

import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;
import com.google.gson.reflect.TypeToken;
import io.github.kouleen.manager.ManagerX;
import io.github.kouleen.manager.domain.ColourTypeEnum;
import io.github.kouleen.manager.domain.PhoneSoulVO;
import io.github.kouleen.manager.domain.ResponseVO;
import io.github.kouleen.manager.domain.TaskScheduledVO;
import io.github.kouleen.minecraft.core.utils.GsonUtils;
import io.github.kouleen.minecraft.core.utils.ObjectUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.logging.Logger;

/**
 * @author zhangqing
 * @since 2025/1/25 14:18
 */
public class TaskScheduledService {

    private static final Random random = new Random();

    private final Logger log;

    private final ManagerX managerX;

    public TaskScheduledService(Logger log, ManagerX managerX) {
        this.log = log;
        this.managerX = managerX;
    }

    public void stopScheduledTask(Long id, Map<Long, TaskScheduledVO> taskScheduledMap, Map<Long, BukkitTask> futureMap) {
        log.info(String.format("停止定时任务 %s", id));
        taskScheduledMap.remove(id);
        BukkitTask future = futureMap.get(id);
        if (Objects.nonNull(future)) {
            log.info(String.format("%s 定时任务已停止",id));
            future.cancel();
            futureMap.remove(id);
        }
    }

    public void startScheduledTask(TaskScheduledVO taskScheduled, Map<Long, TaskScheduledVO> taskScheduledMap, Map<Long, BukkitTask> futureMap,Map<UUID, String> players) {
        log.info(String.format("§2启动定时任务 %s", taskScheduled.getId()));
        String cronExpressionStr = taskScheduled.getCronExpression();
        CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.SPRING);
        CronParser cronParser = new CronParser(cronDefinition);
        Cron cron = cronParser.parse(cronExpressionStr);
        ExecutionTime executionTime = ExecutionTime.forCron(cron);
        ZonedDateTime nowZonedDateTime = ZonedDateTime.now();
        ZonedDateTime nextZonedDateTime = getNext(executionTime, nowZonedDateTime);
        ZonedDateTime endZonedDateTime = getNext(executionTime, nextZonedDateTime);
        long nowEpochSecond = nowZonedDateTime.toEpochSecond();
        long nextEpochSecond = nextZonedDateTime.toEpochSecond();
        long endEpochSecond = endZonedDateTime.toEpochSecond();
        log.info(String.format("§2时间间隔 {%s}秒,第一次间隔{%s}秒", (endEpochSecond - nowEpochSecond), (endEpochSecond - nextEpochSecond)));
        BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
        BukkitTask bukkitTask = bukkitScheduler.runTaskTimer(this.managerX, () -> {
            String taskCommand = taskScheduled.getTaskCommand();
            String[] commands = taskCommand.split(" ");
            StringBuilder stringBuilder = new StringBuilder();
            try {
                Process process = Runtime.getRuntime().exec(commands);
                InputStream inputStream = process.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

                String string;
                while ((string = bufferedReader.readLine()) != null) {
                    stringBuilder.append(string).append("\n");
                }
                process.waitFor();
                String message = stringBuilder.toString();
                ResponseVO<PhoneSoulVO> phoneSoulVOResponseVO = GsonUtils.fromJson(message, new TypeToken<ResponseVO<PhoneSoulVO>>() {}.getType());
                PhoneSoulVO phoneSoulVO = phoneSoulVOResponseVO.getData();
                if(ObjectUtils.isEmpty(phoneSoulVO)){
                    return;
                }
                Collection<? extends Player> onlinePlayers = Bukkit.getOnlinePlayers();
                String title = phoneSoulVO.getTitle();
                String randomColour = ColourTypeEnum.getRandomColour(title, random);
                String context = "[毒鸡汤]: " + randomColour;
                onlinePlayers.forEach(onlinePlayer -> {
                    String playerName = players.get(onlinePlayer.getUniqueId());
                    if(playerName == null || playerName.isEmpty()){
                        onlinePlayer.sendMessage(context);
                    }
                });
            } catch (InterruptedException | IOException var8) {
                throw new RuntimeException(var8);
            }
        }, (nextEpochSecond - nowEpochSecond) * 20, (endEpochSecond - nextEpochSecond) * 20);
        futureMap.put(taskScheduled.getId(), bukkitTask);
        taskScheduledMap.put(taskScheduled.getId(), taskScheduled);
    }

    private static ZonedDateTime getNext(ExecutionTime executionTime, ZonedDateTime zonedDateTime) {
        return executionTime.nextExecution(zonedDateTime).get();
    }
}
